/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { pickedLineData, pickedVertexData, pickedFaceData } from '@amcax/base';
import {
  NumberInputFormat,
  PickInputRJSFFormat,
} from '@app-cad/common/components/command-form/constants';
import { PickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import { getIdOfPickedObj } from '@app-cad/common/utils/render';
import { previewer } from '@app-cad/module';
import { RJSFSchema } from '@rjsf/utils';
import { FeatureBaseCommand, FeaturedCmdDialogParams } from '@app-cad/types';
import { useAsyncEffect } from 'ahooks';
import i18n from 'i18next';
import { useMemo, useState } from 'react';

type pickedDirector = pickedLineData | pickedFaceData;

type FormData = {
  point: pickedVertexData;
  vector: pickedDirector;
  radius: number;
  forward: number;
  back: number;
  reverseVector: boolean;
  reverseForward: boolean;
  reverseBack: boolean;
};

type Params = {
  point: string;
  vector: string;
  radius: number;
  forward: number;
  back: number;
  reverseVector: boolean;
  reverseForward: boolean;
  reverseBack: boolean;
};

// 圆柱面
function CylinderSurface({ title, onClose, props }: FeaturedCmdDialogParams) {
  const initData = {
    point: null,
    vector: null,
    radius: 20,
    forward: 20,
    back: 20,
    reverseVector: false,
    reverseForward: false,
    reverseBack: false,
  };
  const [formData, setFormData] = useState<FormData>(initData);

  const { picker } = useTools();

  useAsyncEffect(async () => {
    if (props == null) {
      setFormData(initData);
      return;
    }

    const params: Params = props.params;
    const {
      radius,
      point,
      vector,
      forward,
      back,
      reverseVector,
      reverseForward,
      reverseBack,
    } = params;

    await initEditDependency([point, vector]);

    setFormData({
      point: picker.generatePickObjByPickID(point) as pickedVertexData,
      vector: picker.generatePickObjByPickID(vector) as pickedDirector,
      radius: radius,
      forward: forward,
      back: back,
      reverseVector: reverseVector,
      reverseForward: reverseForward,
      reverseBack: reverseBack,
    });
  }, []);

  useAsyncEffect(async () => {
    previewer.clear();
    if (!isFormDataValid()) {
      return;
    }
    await execute(true);
  }, [formData]);

  const isFormDataValid = () => {
    const { radius, point, vector, forward, back } = formData;

    return (
      point !== null &&
      vector !== null &&
      radius > 0 &&
      (forward !== 0 || back !== 0)
    );
  };
  const finishValid = useMemo(isFormDataValid, [formData]);
  const checkAndFinish = async () => {
    if (!isFormDataValid()) {
      return;
    }

    await execute(false);

    onClose();
  };

  const { initEditDependency, confirmCommand } = useCommand('cmd-cylinder', {
    commandName: 'CreateSurface',
    editDxid: props?.shape,
    onClose,
    finishDraw: checkAndFinish,
  });

  const execute = async (preview: boolean = false) => {
    const {
      radius,
      point,
      vector,
      forward,
      back,
      reverseVector,
      reverseForward,
      reverseBack,
    } = formData;
    const params: Params = {
      radius: radius,
      point: getIdOfPickedObj(point),
      vector: getIdOfPickedObj(vector),
      forward: forward,
      back: back,
      reverseVector: reverseVector,
      reverseForward: reverseForward,
      reverseBack: reverseBack,
    };
    return confirmCommand(
      {
        type: 'Cylinder',
        a: params,
      },
      preview,
    );
  };

  const schema: RJSFSchema = {
    type: 'object',
    properties: {
      point: {
        type: 'string',
        format: PickInputRJSFFormat.PickVertex,
      },
      vector: {
        type: 'string',
        format: PickInputRJSFFormat.PickDirection,
      },
      reverseVector: {
        type: 'boolean',
        title: '反转方向',
        default: false,
      },
      radius: {
        type: 'number',
        title: '半径',
        format: NumberInputFormat.Length,
      },
      forward: {
        type: 'number',
        title: '向前距离',
        format: NumberInputFormat.Length,
      },
      back: {
        type: 'number',
        title: '向后距离',
        format: NumberInputFormat.Length,
      },
    },
  };

  return (
    <PickableCommandForm
      isFormDataValid={finishValid}
      disabled={false}
      onClose={onClose}
      title={title}
      schema={schema}
      formData={formData}
      onChange={(v) => {
        setFormData(v);
      }}
      extraUiSchema={{
        point: {
          'ui:placeholder': '请输入圆心',
          'ui:autofocus': true,
        },
        vector: {
          'ui:placeholder': '请输入方向',
          'ui:options': {
            showArrow: true,
            allowInfiniteLine: true,
            allowInfinitePlane: true,
          },
        },
        forward: {
          'ui:options': {
            showReverse: true,
            onReverseChange: () => {
              setFormData((prevFormData) => ({
                ...prevFormData,
                reverseForward: !prevFormData?.reverseForward,
              }));
            },
          },
        },
        back: {
          'ui:options': {
            showReverse: true,
            onReverseChange: () => {
              setFormData((prevFormData) => ({
                ...prevFormData,
                reverseBack: !prevFormData?.reverseBack,
              }));
            },
          },
        },
      }}
      submitText='完成'
      onSubmit={checkAndFinish}
    />
  );
}

export const cmdCylinderSurface: FeatureBaseCommand = {
  id: 'CmdCylinderSurface',
  label: 'command.cylinder-surface',
  icon: 'commands/feature/cylinder-surface',
  create: (label, onClose, props) => (
    <CylinderSurface
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
